package com.github.aloxc.plugin.restplus.listener;

import com.github.aloxc.plugin.restplus.common.Consts;
import com.github.aloxc.plugin.restplus.common.KtFunctionHelper;
import com.github.aloxc.plugin.restplus.common.PsiMethodHelper;
import com.github.aloxc.plugin.restplus.component.ServiceModuleNode;
import com.github.aloxc.plugin.restplus.component.ServiceNode;
import com.github.aloxc.plugin.restplus.component.SettingForm;
import com.github.aloxc.plugin.restplus.entity.*;
import com.github.aloxc.plugin.restplus.i18n.I18Bundle;
import com.github.aloxc.plugin.restplus.method.HttpMethod;
import com.github.aloxc.plugin.restplus.navigation.action.RestServiceItem;
import com.github.aloxc.plugin.restplus.navigator.RestServiceDetail;
import com.github.aloxc.plugin.restplus.navigator.RestServicesNavigator;
import com.github.aloxc.plugin.restplus.utils.JsonUtils;
import com.github.aloxc.plugin.restplus.utils.StringUtils;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.util.OpenSourceUtil;
import org.jetbrains.kotlin.idea.KotlinLanguage;
import org.jetbrains.kotlin.psi.KtNamedFunction;

import javax.swing.*;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 服务列表右键处理方案
 *
 * @author leero
 */
public class UrlTreeSelectionListener extends MouseAdapter implements TreeSelectionListener {
    private Project project;
    private final RestServiceDetail myRestServiceDetail;
    private final JTree urlTree;

    public UrlTreeSelectionListener(Project project, RestServiceDetail myRestServiceDetail, JTree urlTree) {
        this.project = project;
        this.myRestServiceDetail = myRestServiceDetail;
        this.urlTree = urlTree;
    }

    /**
     * 显示服务详情
     *
     * @param e
     */
    @Override
    public void valueChanged(TreeSelectionEvent e) {
        DefaultMutableTreeNode node = (DefaultMutableTreeNode) urlTree.getLastSelectedPathComponent();
        if (node == null) {
            return;
        }

        if (node instanceof ServiceNode) {
            ServiceNode serviceNode = (ServiceNode) node;
            RestServiceItem serviceItem = serviceNode.getRestServiceItem();
            myRestServiceDetail.resetRequestTabbedPane();

            String method = serviceItem.getMethod() != null ? String.valueOf(serviceItem.getMethod()) : HttpMethod.GET.name();
            myRestServiceDetail.setMethod(method);
            myRestServiceDetail.setUrl(serviceItem.getFullUrl());
            myRestServiceDetail.setUrlTree(urlTree);
            myRestServiceDetail.setModule(serviceItem.getModule());

            Map<String, Object> requestParams = null;
            String requestBodyJson = "";
            Map<String, Object> requestHeaders = null;
            PsiElement psiElement = serviceItem.getPsiElement();
            String parentName = null;
            boolean foundRequestBody = false;

            if (serviceItem.isSwagger()) {
                requestHeaders = new HashMap<>(16);
                ServiceModuleNode parent = (ServiceModuleNode) serviceNode.getParent();
                String name = parent.getRestServiceProject().getName();
                parentName = name;
                RestConfig restConfig = RestConfig.loadConfig(project);
                String url = null;
                String param = null;

                LABEL1:
                for (SwaggerConfig swaggerConfig : restConfig.getSwaggerConfigList()) {
                    if (swaggerConfig.getName().equals(name)) {
                        List<SwaggerRequest> swaggerRequestList = swaggerConfig.getSwaggerRequestList();
                        LABEL2:
                        for (SwaggerRequest request : swaggerRequestList) {
                            if (request.getUrl().equals(serviceItem.getUrl())) {
                                if (serviceItem.getMethod() == HttpMethod.POST && serviceItem.isFoundRequestBody()) {
                                    if (request.getMethod() == HttpMethod.POST_BODY) {
                                        url = request.getUrl();
                                        param = request.getParam();
                                        foundRequestBody = true;

                                        break LABEL1;
                                    }
                                } else {
                                    if (request.getMethod() == serviceItem.getMethod()) {
                                        url = request.getUrl();
                                        param = request.getParam();
                                        break LABEL1;
                                    }
                                }
                            }
                        }
                        break LABEL1;
                    }
                }
                ArrayList<HashMap<String, Object>> paramList = JsonUtils.toBean(param, ArrayList.class);
//                Map<String, Object> tempMap = paramList.stream().collect(Collectors.toMap(k -> (String) k.get("name"), v -> v.get("value")));
                Map<String, Object> tempMap = new HashMap<>(16);
                for(HashMap<String, Object> pa : paramList){
                    tempMap.put((String) pa.get("name"),pa.get("value"));
                }
                if (foundRequestBody) {
                    requestBodyJson = JsonUtils.toJson(tempMap, false);
                } else {
                    requestParams = tempMap;
                }
            } else {
                if (psiElement.getLanguage() == JavaLanguage.INSTANCE) {
                    PsiMethodHelper psiMethodHelper = PsiMethodHelper.create(serviceItem.getPsiMethod()).withModule(serviceItem.getModule());
                    requestHeaders = psiMethodHelper.buildHeader();
                    requestParams = psiMethodHelper.buildParam();
                    requestBodyJson = psiMethodHelper.buildRequestBodyJson();
                } else if (psiElement.getLanguage() == KotlinLanguage.INSTANCE) {
                    if (psiElement instanceof KtNamedFunction) {
                        KtNamedFunction ktNamedFunction = (KtNamedFunction) psiElement;
                        KtFunctionHelper ktFunctionHelper = KtFunctionHelper.create(ktNamedFunction).withModule(serviceItem.getModule());
                        requestParams = ktFunctionHelper.buildParam();
                        requestBodyJson = ktFunctionHelper.buildRequestBodyJson();
                    }
                }
            }
            myRestServiceDetail.addRequestHeaderTab(requestHeaders);
            myRestServiceDetail.removeResponseTab();
            myRestServiceDetail.addRequestParamsTab(requestParams);
            myRestServiceDetail.addRequestTestTab(null);
            myRestServiceDetail.setUserCase(parentName,method);
            if (StringUtils.isNotBlank(requestBodyJson)) {
                myRestServiceDetail.addRequestBodyTabPanel(requestBodyJson);
            }
        }
    }

    /**
     * 双击urltree的节点跳转到代码
     *
     * @param e
     */
    @Override
    public void mouseClicked(MouseEvent e) {
        super.mouseClicked(e);
        if (e.getSource() == urlTree && e.getClickCount() == 2) {
            // 按照鼠标点击的坐标点获取路径
            TreePath selPath = urlTree.getPathForLocation(e.getX(), e.getY());
            if (selPath != null) {// 谨防空指针异常!双击空白处是会这样
                // 获取这个路径上的最后一个组件,也就是双击的地方
                DefaultMutableTreeNode node = (DefaultMutableTreeNode) selPath.getLastPathComponent();
                if (node instanceof ServiceNode) {
                    ServiceNode serviceNode = (ServiceNode) node;
                    RestServiceItem myServiceItem = serviceNode.getRestServiceItem();
                    PsiElement psiElement = myServiceItem.getPsiElement();
                    if (!serviceNode.isSwagger()) {
                        //只有不是swagger的才跳到源码
                        if (!psiElement.isValid()) {
                            // PsiDocumentManager.getInstance(psiMethod.getProject()).commitAllDocuments();
                            // try refresh service
//                RestServicesNavigator.getInstance(myServiceItem.getModule().getProject()).scheduleStructureUpdate();
                            project.getComponent(RestServicesNavigator.class).scheduleStructureUpdate();

                        }

                        if (psiElement.getLanguage() == JavaLanguage.INSTANCE) {
                            PsiMethod psiMethod = myServiceItem.getPsiMethod();
                            OpenSourceUtil.navigate(psiMethod);

                        } else if (psiElement.getLanguage() == KotlinLanguage.INSTANCE) {
                            if (psiElement instanceof KtNamedFunction) {
                                KtNamedFunction ktNamedFunction = (KtNamedFunction) psiElement;
                                OpenSourceUtil.navigate(ktNamedFunction);
                            }
                        }
                    }
                }
            }
        }
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        super.mouseReleased(e);
        TreePath selected = urlTree.getPathForLocation(e.getX(), e.getY());
        if (selected == null) {
            return;
        }
        urlTree.setSelectionPath(selected);
        DefaultMutableTreeNode selNode = (DefaultMutableTreeNode) urlTree.getLastSelectedPathComponent();
        if (e.isPopupTrigger() && selNode instanceof ServiceNode) {
            if (selected != null) {
                urlTree.setSelectionPath(selected);
                //创建保存菜单
                JPopupMenu menu = new JPopupMenu();

                JMenuItem env = new JMenuItem(I18Bundle.getMessage("com.github.aloxc.plugin.restplus.request.setting.text"));
                env.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
                env.setIcon(Consts.Icons.ENVIROMENT16);
                menu.add(env);
                env.addActionListener(myRestServiceDetail.getRequestEnvironmentListener());

                JMenuItem copyUrl = new JMenuItem(I18Bundle.getMessage("com.github.aloxc.plugin.restplus.request.copyurl.text"));
                copyUrl.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
                copyUrl.setIcon(Consts.Icons.URL);
                menu.add(copyUrl);
                copyUrl.addActionListener(myRestServiceDetail.getCopyUrlActionListener(urlTree));

                JMenuItem copyFullUrl = new JMenuItem(I18Bundle.getMessage("com.github.aloxc.plugin.restplus.request.copyfullurl.text"));
                copyFullUrl.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
                copyFullUrl.setIcon(Consts.Icons.FULL_URL);
                menu.add(copyFullUrl);
                copyFullUrl.addActionListener(myRestServiceDetail.getCopyUrlActionListener(urlTree));

                if(!((ServiceNode) selNode).getRestServiceItem().isSwagger()) {
                    Module module = ((ServiceNode) selNode).getRestServiceItem().getModule();
                    RestConfig config = RestConfig.loadConfig(project);
                    Yapi yapi = config.getYapi(module);
                    JMenuItem pushYapi = null;
                    if (yapi == null || StringUtils.isNullOrEmpty(yapi.getToken()) || StringUtils.isNullOrEmpty(yapi.getProjectId()) || StringUtils.isNullOrEmpty(yapi.getUrl())) {
                        pushYapi = new JMenuItem(I18Bundle.getMessage("com.github.aloxc.plugin.restplus.request.pushyapi.noconfig.text"));
                        //未配置yapi，弹出配置
                        pushYapi.addActionListener(ae -> {
                            SettingForm settingForm = new SettingForm(project);
                            SettingListenerContext context = new SettingListenerContext();
                            context.setSettingFormType(SettingFormType.YAPI);
                            context.setContext(module.getName());
                            SettingListener settingListener = new SettingListener(settingForm, context);
                            settingListener.actionPerformed(null);
                        });
                    } else {
                        pushYapi = new JMenuItem(I18Bundle.getMessage("com.github.aloxc.plugin.restplus.request.pushyapi.text"));
                        pushYapi.addActionListener(myRestServiceDetail.getPushYapiActionListener(urlTree));
                    }
                    pushYapi.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
                    pushYapi.setIcon(Consts.Icons.PUSH_YAPI);
                    menu.add(pushYapi);
                }

                menu.show(urlTree, e.getX(), e.getY());
            }
        }
    }
}
